package at.ac.tuwien.dse.health.event.listener;

import at.ac.tuwien.dse.health.event.bus.EventBus;
import at.ac.tuwien.dse.health.event.bus.EventTarget;
import at.ac.tuwien.dse.health.event.type.Event;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.utils.SerializationUtils;

import javax.annotation.PostConstruct;
import java.io.Serializable;

import static com.google.common.base.Preconditions.checkState;

/**
 * Uses a {@link RabbitTemplate} to send and receive {@link Message Messages} containing {@link Event Events}.
 *
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 */
public class RabbitEventListener implements MessageListener, EventListener {
	private static final Logger LOGGER = LogManager.getLogger(RabbitEventListener.class);
	RabbitTemplate rabbitTemplate;
	EventBus eventBus;

	/**
	 * Checks whether this {@link RabbitEventListener} is initialized properly.
	 * <p/>
	 * At least one of the following conditions must be true:
	 * <ul>
	 * <li>{@code eventBus} is not {@code null}</li>
	 * <li>{@code rabbitTemplate} is not {@code null}</li>
	 * </ul>
	 */
	@PostConstruct
	public void init() {
		checkState(rabbitTemplate != null || eventBus != null, "Either 'eventBus' and/or 'rabbitTemplate' must not be null.");
	}

	@Override
	public void handleEvent(EventTarget eventTarget, final Event<? extends Serializable> event) {
		checkState(rabbitTemplate != null, "JmsTemplate not available. Please configure %s properly.", getClass());
		rabbitTemplate.send(new Message(SerializationUtils.serialize(event), new MessageProperties()));
	}

	@Override
	public void onMessage(Message message) {
		checkState(eventBus != null, "EventBus not available. Please configure %s properly.", getClass());
		Event<?> event = (Event<?>) SerializationUtils.deserialize(message.getBody());
		eventBus.delegate(event);
	}

	public void setRabbitTemplate(RabbitTemplate rabbitTemplate) {
		this.rabbitTemplate = rabbitTemplate;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}
}
